/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package game.experts.combine;

import analysys.HECAlignmentHit;
import game.datahandling.dataenvelopes.base.PrimaryStructure;
import game.encodings.OutputEncoding;
import game.experts.Expert;
//import utils.Msg;
import utils.Profile;
import utils.ProfileMatrix;

/**
 *
 * @author emanuele
 */
public class SSPSingleHECWeightHintedCombinerExpert extends SSPBaseHintedCombinerExpert {

    protected double[] getHECWeight(Expert<PrimaryStructure> e) {
        double[] hecweight = new double[3];
        double hweight, eweight, cweight,
                herrorrate, eerrorrate, cerrorrate,
                hsum, esum, csum;

        if (this.current.hints.isEmpty()) {
            hecweight[0] = hecweight[1] = hecweight[2] = 1.0;
            return hecweight;
        }

        hsum = esum = csum = 0;
        for (HECAlignmentHit hint: this.current.hints) {
            OutputEncoding enc = e.predict(new PrimaryStructure(hint.hitWholePri));
            Profile p = enc.getProfile();
            String prediction = enc.decode().toString();
            
            double errors = this.getDifferences(prediction, hint.hitWholeSec);

            double currerrorrate = errors / ((double)prediction.length());

            double hcert = 0, ecert = 0, ccert = 0;
            double hnumb = 0, enumb = 0, cnumb = 0;
            for (int i = 0; i < prediction.length(); i++) {
                if (prediction.charAt(i) == 'H') {
                    hcert += p.get(0, i);
                    hnumb++;
                } else if (prediction.charAt(i) == 'E') {
                    ecert += p.get(1, i);
                    enumb++;
                } else {
                    ccert += p.get(2, i);
                    cnumb++;
                }
            }
            hcert = hcert / (hnumb + 0.5);
            ecert = ecert / (enumb + 0.5);
            ccert = ccert / (cnumb + 0.5);

            hsum += currerrorrate*hcert;
            esum += currerrorrate*ecert;
            csum += currerrorrate*ccert;
        }

        double length = this.current.hints.size();
        herrorrate = (hsum + 0.5) / length;
        eerrorrate = (esum + 0.5) / length;
        cerrorrate = (csum + 0.5) / length;
//        weight = 1 / (1 - accuracy);
//        weight = 1 / Math.pow((1 - accuracy), 5);
//        weight = -Math.log((1 - accuracy));
        hweight = Math.pow(Math.exp(1 / herrorrate), 3); // Best performance, must try with different powers
        eweight = Math.pow(Math.exp(1 / eerrorrate), 3); // Best performance, must try with different powers
        cweight = Math.pow(Math.exp(1 / cerrorrate), 3); // Best performance, must try with different powers

        hecweight[0] = hweight;
        hecweight[1] = eweight;
        hecweight[2] = cweight;
        return hecweight;
    }

    @Override
    protected Profile mergePredictions(OutputEncoding[] allPredictions) {
        Profile ret;

        ret = new ProfileMatrix(3, this.current.input.length(), 0);
        for (int i = 0; i < allPredictions.length; i++) {
            Profile p;
            double[] hecweight;

            hecweight = this.getHECWeight(this.experts.get(i));

            p = allPredictions[i].getProfile();

            for (int j = 0; j < p.length(); j++) {
                p.set(0, j, p.get(0, j) * hecweight[0]);
                p.set(1, j, p.get(1, j) * hecweight[1]);
                p.set(2, j, p.get(2, j) * hecweight[2]);
            }

            ret.add(p);
        }
        ret.normalizeColumns();

        return ret;
    }
}
